package com.kin207.netty.session;

import java.net.SocketAddress;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.eventbus.EventBus;
import com.kin207.netty.listener.IEventBusListener;
import com.kin207.netty.listener.eventbus.CreatedListenerEvent;
import com.kin207.netty.listener.eventbus.DestroyedListenerEvent;
import com.kin207.netty.msg.IMessageSend;
import com.kin207.netty.udp.UdpChannelHandlerContext;

import io.netty.channel.ChannelHandlerContext;

public abstract class SessionManagerAbs implements ISessionManager,IMessageSend, IEventBusListener<Session> {
	final static Logger logger = LoggerFactory.getLogger(SessionManagerAbs.class);
	
	protected String messageEnd = "\n";
	protected Map<String,Session> sessions = new ConcurrentHashMap();
	protected Map<String,String> names = new ConcurrentHashMap();
	protected Map<String,Set<String>> groups = new ConcurrentHashMap();
	protected Map<String,Set<String>> onoff = new ConcurrentHashMap();
	protected EventBus eventBus;
	public Session addSession(ChannelHandlerContext ctx){
		String key = ctx.channel().remoteAddress().toString();
		Session session = sessions.get(key);
		if(session==null){
			logger.debug("add session, address:{}.", key);
			session = new Session(key, this, ctx);
			sessions.put(key, session);
			postCreatedEvent(session);
		}
		session.lastActive();
		return session;
	}
	
	public Session addSession(SocketAddress socketAddress, ChannelHandlerContext ctx){
		UdpChannelHandlerContext udpctx = new UdpChannelHandlerContext(ctx, socketAddress);
		return addSession(udpctx);
	}
	
	public Session removeSession(ChannelHandlerContext ctx){
		logger.debug("remove session, address:{}", ctx.channel().remoteAddress());
		return removeSession(ctx.channel().remoteAddress().toString());
	}
	
	public Session getSession(ChannelHandlerContext ctx){
		String cid = ctx.channel().remoteAddress().toString();
		return sessions.get(cid);
	}
	
	public Session removeSession(String key){
		Session session = sessions.remove(key);
		postDestroyedEvent(session);
		return session;
	}
	
	public int sessions(){
		return sessions.size();
	}
	
	public boolean addName(String name, ChannelHandlerContext ctx){
		String cid = ctx.channel().remoteAddress().toString();
		if(name.equals("FFFFFFFF")||name.equals("AAAAAAAA")||names.containsKey(name)){
			return false;
		}
		logger.debug("add name, address:{},---- names:{}", ctx.channel().remoteAddress(),names.entrySet());
		Session session = sessions.get(cid);
		if(names.get("name")!=null && !names.get("name").equals(cid)){
			names.remove(session.getName());
		}
		names.put(name, cid);
		session.setName(name);
		logger.debug("add name, address:{}, name:{}", ctx.channel().remoteAddress(), name);
		return true;
	}
	
	public Session removeName(ChannelHandlerContext ctx){
		String cid = ctx.channel().remoteAddress().toString();
		Session session = sessions.get(cid);
		logger.debug("remove name, address:{}, name:{}", ctx.channel().remoteAddress(), session.getName());
		names.remove(session.getName());
		session.setName(null);
		return session;
	}
	
	public int names(){
		return names.size();
	}
	
	public void addGroup(String groupName, ChannelHandlerContext ctx){
		logger.debug("add group, address:{}, group:{}", ctx.channel().remoteAddress(), groupName);
		Set<String> groupSet = groups.get(groupName);
		if(groupSet==null){//骞跺彂鏈鐞�
			logger.debug("create group:{}", groupName);
			groupSet = new HashSet();
			groups.put(groupName, groupSet);
		}
		String cid = ctx.channel().remoteAddress().toString();
		Session session = sessions.get(cid);
		groupSet.add(cid);
		session.addGroup(groupName);
	}
	
	public int removeGroup(String groupName, ChannelHandlerContext ctx){
		logger.debug("remove group, address:{}, group:{}", ctx.channel().remoteAddress(), groupName);
		Set<String> groupSet = groups.get(groupName);
		if(groupSet!=null){
			String cid = ctx.channel().remoteAddress().toString();
			Session session = sessions.get(cid);
			groupSet.remove(cid);
			session.removeGroup(groupName);
			if(groupSet.size()==0){//骞跺彂鏈鐞�
				logger.debug("close group, address:{}, group:{}", ctx.channel().remoteAddress(), groupName);
				groups.remove(groupName);
				return 1;
			}
			return 2;
		}
		return 0;
	}
	
	public int groups(){
		return groups.size();
	}
	
	public int close(ChannelHandlerContext ctx){
		logger.debug("close session, address:{} .", ctx.channel().remoteAddress());
		String cid = ctx.channel().remoteAddress().toString();
		Session session = sessions.get(cid);
		if(session==null){
			return 1;
		}
		if(session.getName()!=null){
			logger.debug("close session, remove name:{} .", session.getName());
			names.remove(session.getName());
		}
		if(session.getGroups()!=null){
			for(String group : session.getGroups()){
				logger.debug("close session, remove group:{} .", group);
				removeGroup(group, ctx);
			}
		}
		removeSession(cid);
		return 0;
	}
	
	public void postCreatedEvent(Session o) {
		if(getEventBus()!=null){
			logger.debug("event bus post CreatedListenerEvent<Session>{}", o);
			getEventBus().post(new CreatedListenerEvent<Session>(o));
		}
	}

	public void postDestroyedEvent(Session o) {
		if(getEventBus()!=null){
			logger.debug("event bus post DestroyedListenerEvent<Session>{}", o);
			getEventBus().post(new DestroyedListenerEvent<Session>(o));
		}
	}
	
	public void setMessageEnd(String messageEnd){
		this.messageEnd = messageEnd;
	}
	
	public String getMessageEnd(){
		return this.messageEnd;
	}

	public Map<String, Session> getSessions() {
		return sessions;
	}

	public Map<String, Set<String>> getGroups() {
		return groups;
	}

	public void setNames(Map<String, String> names) {
		this.names = names;
	}

	public EventBus getEventBus() {
		return eventBus;
	}

	public void setEventBus(EventBus eventBus) {
		this.eventBus = eventBus;
	}
	
	
}
